package cn.stylefeng.guns.modular.api.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.stylefeng.guns.base.pojo.page.LayuiPageFactory;
import cn.stylefeng.guns.base.pojo.page.LayuiPageInfo;
import cn.stylefeng.guns.modular.api.entity.*;
import cn.stylefeng.guns.modular.api.mapper.*;
import cn.stylefeng.guns.modular.api.model.enums.PlanStatusEnum;
import cn.stylefeng.guns.modular.api.model.enums.TaskTypeEnum;
import cn.stylefeng.guns.modular.api.model.params.PlanParam;
import cn.stylefeng.guns.modular.api.model.params.TaskParam;
import cn.stylefeng.guns.modular.api.model.params.TaskRecordParam;
import cn.stylefeng.guns.modular.api.model.result.ERPValueItem;
import cn.stylefeng.guns.modular.api.model.result.PlanResult;
import cn.stylefeng.guns.modular.api.model.result.TaskRecordResult;
import  cn.stylefeng.guns.modular.api.service.PlanService;
import cn.stylefeng.guns.modular.api.service.TaskRecordService;
import cn.stylefeng.guns.modular.api.service.TaskService;
import cn.stylefeng.guns.sys.core.constant.state.LogSucceed;
import cn.stylefeng.guns.sys.core.constant.state.LogType;
import cn.stylefeng.guns.sys.core.log.factory.LogFactory;
import cn.stylefeng.roses.core.util.ToolUtil;
import cn.stylefeng.roses.kernel.model.exception.ServiceException;
import com.alibaba.druid.support.json.JSONUtils;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * <p>
 * 生产计划 服务实现类
 * </p>
 *
 * @author wusonghe
 * @since 2019-08-31
 */
@Service
@Slf4j
public class PlanServiceImpl extends ServiceImpl<PlanMapper, Plan> implements PlanService {

    @Autowired
    MaterielMapper materielMapper;

    @Autowired
    ProductMapper productMapper;

    @Autowired
    TaskService taskService;

    @Autowired
    TaskRecordService taskRecordService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(PlanParam param) throws Exception {


        try {
            //1.先减少仓库
            List<ERPValueItem> erpValueItems = JSONObject.parseArray(param.getMaterielList(), ERPValueItem.class);
            for (ERPValueItem erpValueItem: erpValueItems) {
                Materiel materiel = materielMapper.selectById(Integer.parseInt(erpValueItem.getValue()));

                Integer subNumber =  Integer.parseInt(erpValueItem.getNumber());



                int leftUseNumber = materiel.getNumber() - materiel.getUnuseNumber() - subNumber;
                if (leftUseNumber<0) {
                    throw new ServiceException(500, "原料超出仓库容量");
                 }
                Integer leftNumber = materiel.getNumber() - subNumber;
                materiel.setNumber(leftNumber);
                materielMapper.updateById(materiel);
            }
            List<ERPValueItem> productErpValueItems = JSONObject.parseArray(param.getPlanProductList(), ERPValueItem.class);
            if (productErpValueItems!=null){
                param.setGrowNumber(productErpValueItems.size());
            }

            //计划保存
            Long planId = Math.abs(new Random().nextLong());
            Plan entity = getEntity(param);
            entity.setPlanId(planId);
            this.save(entity);

            //3.计划任务
            param.setPlanId(planId);
            saveTask(param,false);

            //日志
//            LogFactory.createOperationLog(LogType.PLAN,param.getPlanId(),
//                    "计划日志",
//                    null,
//                    "更新计划",
//                    JSONUtils.toJSONString(entity),
//                    LogSucceed.SUCCESS);


        }catch (Exception e) {
            log.error(e.getMessage());
            throw new ServiceException(500,e.getMessage());
        }
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(PlanParam param){


        if (param.getStatus().equals(PlanStatusEnum.DONE)) {

            List<ERPValueItem> erpValueItems = JSONObject.parseArray(param.getProductList(), ERPValueItem.class);
            for (ERPValueItem erpValueItem: erpValueItems) {
                Product product = productMapper.selectById(Integer.parseInt(erpValueItem.getValue()));
                Integer subNumber =  Integer.parseInt(erpValueItem.getNumber());
                product.setNumber(product.getNumber()+subNumber);
                product.setWeight(Double.parseDouble(erpValueItem.getWeight()));
                product.setPoodId(param.getPoodId());
                product.setFarmId(param.getFarmId());
                productMapper.updateById(product);

            }
        }

        List<ERPValueItem> productErpValueItems = JSONObject.parseArray(param.getPlanProductList(), ERPValueItem.class);
        if (productErpValueItems!=null){
            param.setGrowNumber(productErpValueItems.size());
        }


        Plan oldEntity = getOldEntity(param);
        Plan newEntity = getEntity(param);
        ToolUtil.copyProperties(newEntity, oldEntity);
        this.updateById(newEntity);

        //任务更新
        this.saveTask(param,true);
    }

    private void saveTask(PlanParam param,Boolean isUpdate){

        Long planId = param.getPlanId();

        //计算时间
        Date startDate = DateUtil.parse(param.getReleaseStartTime()).toJdkDate();
        Date todayDate = new Date();
        //整理数据
        Map<String,Object> map = new HashMap<String,Object>();
        if (StringUtils.isNotEmpty(param.getSelectDayMaterials())){
            map.put("materiel",param.getSelectDayMaterials());
        }
        if (StringUtils.isNotEmpty(param.getSelectDayOthers())){
            map.put("other",param.getSelectDayOthers());
        }
        String dayContent = "";
        if (map.size() > 0) {
            dayContent = JSONObject.toJSONString(map);
        }

        Map<String,Object> weekMap = new HashMap<String,Object>();
        if (StringUtils.isNotEmpty(param.getSelectWeekMaterials())){
            weekMap.put("materiel",param.getSelectWeekMaterials());
        }
        if (StringUtils.isNotEmpty(param.getSelectWeekOthers())){
            weekMap.put("other",param.getSelectWeekOthers());
        }
        String weekContent = "";
        if (weekMap.size() > 0) {
            weekContent = JSONObject.toJSONString(weekMap);
        }

        Map<String,Object> mouthMap = new HashMap<String,Object>();
        if (StringUtils.isNotEmpty(param.getSelectMouthMaterials())){
            mouthMap.put("materiel",param.getSelectMouthMaterials());
        }
        if (StringUtils.isNotEmpty(param.getSelectMouthOthers())){
            mouthMap.put("other",param.getSelectMouthOthers());
        }
        String mouthContent = "";
        if (map.size() > 0) {
            mouthContent = JSONObject.toJSONString(mouthMap);
        }


        //更新数据
        if (isUpdate) {
            TaskParam oldTaskParam = new TaskParam();
            oldTaskParam.setPlanId(planId);
            List<Task> oldTaskList = taskService.findListBySpec(oldTaskParam);
            for (Task task: oldTaskList){
                //更新计划相关的任务内容
                TaskParam taskParam = new TaskParam();
                if (task.getType().equals(TaskTypeEnum.DAY.getCode().longValue())) {
                    task.setContent(dayContent);
                }else if (task.getType().equals(TaskTypeEnum.WEEK.getCode().longValue())) {
                    task.setContent(weekContent);
                }else if (task.getType().equals(TaskTypeEnum.MOUTH.getCode().longValue())) {
                    task.setContent(mouthContent);
                }
                BeanUtils.copyProperties(task,taskParam);
                taskService.update(taskParam);

                //更新最新任务记录的内容
                TaskRecordParam taskRecordParam = new TaskRecordParam();
                taskRecordParam.setTaskId(task.getTaskId());
                taskRecordParam.setType(task.getType().intValue());
                TaskRecordResult taskRecordResult =  taskRecordService.findBySpec(taskRecordParam);
                taskRecordResult.setRecord(task.getContent());
                BeanUtils.copyProperties(taskRecordResult,taskRecordParam);
                taskRecordService.update(taskRecordParam);
            }
        }else {

            //增加任务记录
            List<Task> taskList = new ArrayList<>();
            List<TaskRecord> taskRecordList = new ArrayList<>();

            ////日任务
            if (StringUtils.isNotEmpty(param.getSelectDayMaterials()) || StringUtils.isNotEmpty(param.getSelectDayOthers())) {

                TaskParam taskParam = new TaskParam();
                Long taskId = Math.abs(new Random().nextLong());
                taskParam.setTaskId(taskId);
                taskParam.setPlanId(planId);
                taskParam.setContent(dayContent);
                if (dayContent.length() == 0) {
                    taskParam.setContent("暂无");
                }
                taskParam.setType(TaskTypeEnum.DAY.getCode().longValue());
                taskParam.setStartTime(param.getReleaseStartTime());
                taskParam.setEndTime(param.getReleaseEndTime());
                taskParam.setWorker(param.getWorker());
                taskParam.setReviewWorker(param.getReviewWorker());
                taskParam.setTitle("日任务-生产计划-" + planId.toString());
                Task task = new Task();
                BeanUtils.copyProperties(taskParam,task);
                taskList.add(task);

                //生成任务记录列表
                if (dayContent.length() > 0) {
                    taskRecordList.addAll(getTaskRecordList(startDate,dayContent,taskId,planId,TaskTypeEnum.DAY));
                }

            }
            ////周任务
            if (StringUtils.isNotEmpty(weekContent)) {
                TaskParam taskParam = new TaskParam();
                Long taskId = Math.abs(new Random().nextLong());
                taskParam.setTaskId(taskId);
                taskParam.setPlanId(planId);
                taskParam.setContent(weekContent);
                if (weekContent.length() == 0) {
                    taskParam.setContent("暂无");
                }
                taskParam.setType(TaskTypeEnum.WEEK.getCode().longValue());
                taskParam.setStartTime(param.getReleaseStartTime());
                taskParam.setEndTime(param.getReleaseEndTime());
                taskParam.setWorker(param.getWorker());
                taskParam.setReviewWorker(param.getReviewWorker());
                taskParam.setTitle("周任务-生产计划-" + planId.toString());
                Task task = new Task();
                BeanUtils.copyProperties(taskParam,task);
                taskList.add(task);

                //生成任务记录列表
                if (weekContent.length() > 0) {
                    taskRecordList.addAll(getTaskRecordList(startDate,weekContent,taskId,planId,TaskTypeEnum.WEEK));

                }

            }
            ////月任务
            if (StringUtils.isNotEmpty(mouthContent)) {



                TaskParam taskParam = new TaskParam();
                Long taskId = Math.abs(new Random().nextLong());
                taskParam.setTaskId(taskId);
                taskParam.setPlanId(planId);
                taskParam.setContent(mouthContent);
                if (mouthContent.length() == 0) {
                    taskParam.setContent("暂无");
                }
                taskParam.setType(TaskTypeEnum.MOUTH.getCode().longValue());
                taskParam.setStartTime(param.getReleaseStartTime());
                taskParam.setEndTime(param.getReleaseEndTime());
                taskParam.setWorker(param.getWorker());
                taskParam.setReviewWorker(param.getReviewWorker());
                taskParam.setTitle("月任务-生产计划-" + planId.toString());
                Task task = new Task();
                BeanUtils.copyProperties(taskParam,task);
                taskList.add(task);
                //生成任务记录列表
                if (mouthContent.length() > 0) {
                    taskRecordList.addAll(getTaskRecordList(startDate,mouthContent,taskId,planId,TaskTypeEnum.MOUTH));
                }
            }
            //4.批量插入任务
            taskService.saveAll(taskList);
            taskRecordService.saveAll(taskRecordList);
        }



    }
    private List<TaskRecord> getTaskRecordList( Date startDate,
                                               String content,
                                               Long taskId,
                                               Long planId,
                                               TaskTypeEnum taskTypeEnum) {
        List<TaskRecord> taskRecords = new ArrayList<>();
        Long diff = 1L; //只生产一个
        for (Integer i = 0; i < diff; i++) {

            TaskRecordParam taskRecordParam = new TaskRecordParam();
            taskRecordParam.setRecord(content);
            taskRecordParam.setTaskId(taskId);
            taskRecordParam.setPlanId(planId);
            taskRecordParam.setType(taskTypeEnum.getCode());

            if (taskTypeEnum.equals(TaskTypeEnum.DAY)) {
                Date date =  DateUtils.addDays(startDate,i);
                String reportDate = DateUtil.formatDate(date);
                taskRecordParam.setReportDate(reportDate);
                taskRecordParam.setTitle(String.format("日任务-%s",reportDate));
            }else if (taskTypeEnum.equals(TaskTypeEnum.WEEK)){
                Date date =  DateUtils.addDays(startDate,7);
                String startDateStr = DateUtil.formatDate(startDate);
                String reportDateStr = DateUtil.formatDate(date);
                taskRecordParam.setReportDate(String.format("%s到%s",startDateStr,reportDateStr));
                taskRecordParam.setTitle(String.format("周任务-第%d周",i+1));
            }else {
                Date date =  DateUtils.addDays(startDate,30);
                String startDateStr = DateUtil.formatDate(startDate);
                String reportDateStr = DateUtil.formatDate(date);
                taskRecordParam.setReportDate(String.format("%s到%s",startDateStr,reportDateStr));
                taskRecordParam.setTitle(String.format("月任务-第%d月",i+1));
            }


            TaskRecord taskRecord = new TaskRecord();
            BeanUtils.copyProperties(taskRecordParam,taskRecord);
            taskRecords.add(taskRecord);
        }
        return taskRecords;

    }

    @Override
    @Transactional(rollbackFor = ServiceException.class)
    public void delete(PlanParam param){

        try {
            Long planId = param.getPlanId();
            this.removeById(planId);

            TaskParam taskParam = new TaskParam();
            taskParam.setPlanId(planId);
            taskService.delete(taskParam);

            TaskRecordParam taskRecordParam = new TaskRecordParam();
            taskRecordParam.setPlanId(planId);
            taskRecordService.delete(taskRecordParam);
        }catch (Exception e){
            throw new ServiceException(500,e.getMessage());
        }


    }



    @Override
    public PlanResult findBySpec(PlanParam param){
        return null;
    }

    @Override
    public List<PlanResult> findListBySpec(PlanParam param){
        return this.baseMapper.customList(param);
    }

    @Override
    public LayuiPageInfo findPageBySpec(PlanParam param){
        Page pageContext = getPageContext();
        if (pageContext.getSize()==0) {
            List datas =  this.baseMapper.customList(param);
            return LayuiPageFactory.createDataInfo(datas);
        }
        IPage page = this.baseMapper.customPageList(pageContext, param);
        return LayuiPageFactory.createPageInfo(page);
    }

    private Serializable getKey(PlanParam param){
        return param.getPlanId();
    }

    private Page getPageContext() {
        return LayuiPageFactory.defaultPage();
    }

    private Plan getOldEntity(PlanParam param) {
        return this.getById(getKey(param));
    }

    private Plan getEntity(PlanParam param) {
        Plan entity = new Plan();
        ToolUtil.copyProperties(param, entity);
        return entity;
    }

}
